/***************************************************************************************
 * Copyright 2020 Infineon Technologies AG ( www.infineon.com ).                       *
 * All rights reserved.                                                                *
 *                                                                                     *
 * Licensed  Material-Property of Infineon Technologies AG.                            *
 * This software is made available solely pursuant to the terms of Infineon            *
 * Technologies AG agreement which governs its use. This code and the information      *
 * contained in it are proprietary and confidential to Infineon Technologies AG.       *
 * No person is allowed to copy, reprint, reproduce or publish any part of this code,  *
 * nor disclose its contents to others, nor make any use of it, nor allow or assist    *
 * others to make any use of it - unless by prior Written express authorization of     *
 * Infineon Technologies AG and then only to the extent authorized.                    *
 *                                                                                     *
 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,            *
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY,           *
 * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT, ARE DISCLAIMED.  IN NO       *
 * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,     *
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,                 *
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;         *
 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY             *
 * WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR            *
 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF              *
 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.                                          *
 *                                                                                     *
 ***************************************************************************************/
/**
 * @file   interface.c
 * @date   June, 2020
 * @brief  Implementation of communication interface
 */

#include "auths_api.h"
#include "auths_config.h"
#include "auths_status.h"
#include "i2c_bus_command.h"

extern AuthS_Capability auths_capability;

/** @brief Device register attributes */
const struct register_attribute_ {
    uint16_t register_name;
    Register_Access access;
}register_attribute[] = {
	{ AUTHS_SFR_USER_NVM_LOCK_1, ACCESS_AFTER_HOST_AUTH },
 	{ AUTHS_SFR_USER_NVM_LOCK_2, ACCESS_AFTER_HOST_AUTH },
	{ AUTHS_SFR_USER_NVM_LOCK_3, ACCESS_AFTER_HOST_AUTH },
  	{ AUTHS_SFR_USER_NVM_LOCK_4, ACCESS_AFTER_HOST_AUTH },
 	{ AUTHS_SFR_USER_NVM_LOCK_5, ACCESS_AFTER_HOST_AUTH },
 	{ AUTHS_SFR_USER_NVM_LOCK_6, ACCESS_AFTER_HOST_AUTH },
    { AUTHS_SFR_USER_NVM_LOCK_STS_1, ACCESS_ALWAYS },
    { AUTHS_SFR_USER_NVM_LOCK_STS_2, ACCESS_ALWAYS },
    { AUTHS_SFR_USER_NVM_LOCK_STS_3, ACCESS_ALWAYS },
    { AUTHS_SFR_USER_NVM_LOCK_STS_4, ACCESS_ALWAYS },
    { AUTHS_SFR_USER_NVM_LOCK_STS_5, ACCESS_ALWAYS },
    { AUTHS_SFR_USER_NVM_LOCK_STS_6, ACCESS_ALWAYS },

	{ AUTHS_SFR_LSC_KILL_CTRL, ACCESS_AFTER_HOST_AUTH },
    { AUTHS_SFR_LSC_KILL_CONF_1, ACCESS_AFTER_HOST_AUTH },
    { AUTHS_SFR_LSC_KILL_CONF_2, ACCESS_AFTER_HOST_AUTH },
    { AUTHS_SFR_LSC_KILL_FEAT_STS_1, ACCESS_AFTER_HOST_AUTH },

	{ AUTHS_SFR_LSC_KILL_FEAT_STS_2, ACCESS_ALWAYS },
    { AUTHS_SFR_LSC_KILL_ACT_STS_1, ACCESS_ALWAYS },
    { AUTHS_SFR_LSC_KILL_ACT_STS_2, ACCESS_ALWAYS },
	{ AUTHS_SFR_BUSY_STS, ACCESS_ALWAYS },
    { AUTHS_SFR_DEVICE_ADDR, ACCESS_ALWAYS },
    { AUTHS_SFR_LOCK_STS, ACCESS_ALWAYS },
	
	{ AUTHS_SFR_LSC_DEC_VAL_L, ACCESS_AFTER_HOST_AUTH },
    { AUTHS_SFR_LSC_DEC_VAL_H, ACCESS_AFTER_HOST_AUTH },

    { AUTHS_SFR_SWI_CONF_0, ACCESS_ALWAYS },
	{ AUTHS_SFR_SWI_CONF_1, ACCESS_ALWAYS },

    { AUTHS_SFR_SWI_STS_0, ACCESS_ALWAYS },
	{ AUTHS_SFR_SWI_STS_1, ACCESS_ALWAYS },
    { AUTHS_SFR_SWI_STS_2, ACCESS_ALWAYS },

    { AUTHS_SFR_SWI_INT_0, ACCESS_ALWAYS },
	{ AUTHS_SFR_SWI_INT_1, ACCESS_ALWAYS },

 	{ AUTHS_SFR_SWI_DADR0_L, ACCESS_ALWAYS },
    { AUTHS_SFR_SWI_DADR0_H, ACCESS_ALWAYS },

    { AUTHS_SFR_SWI_RD_LEN, ACCESS_ALWAYS },
	{ AUTHS_SFR_SWI_WD_LEN, ACCESS_ALWAYS },

    { AUTHS_SFR_GPO_CTRL, ACCESS_ALWAYS },
    { AUTHS_SFR_GPO_CTRL_STS, ACCESS_ALWAYS },
	{ 0xFFFF, ACCESS_ALWAYS },
};

/**
* @brief Check for valid I2C address
* @param i2c_address I2C address of the device
*/
static uint16_t register_counter(void){
	uint16_t count=0;
	while(1){
		if(register_attribute[count].register_name != 0xFFFF){
			count++;
		}
		else{
			break;
		}
	}

	return count;
}

/**
* @brief Check for valid I2C address
* @param i2c_address I2C address of the device
*/
static uint16_t Is_I2C_address_valid(uint8_t i2c_address){
	//Authenticate S only support 7-bit address
	//A6-A5-A4-A3-A2-A1-A0-(RW)
	//MSB=A6, LSB=(RW)
	if((i2c_address <= 0x10) || (i2c_address >= 0x80) ){
		return INF_I2C_E_ADDRESS;
	}else{
		return INF_I2C_SUCCESS;
	}
}

//Check register access
static uint16_t Can_Access_Register(uint16_t uw_Address)
{
	uint8_t i=0;
	uint16_t register_count = register_counter();

#if (HOST_AUTHENTICATION_FEATURE_SUPPORTED==0)
	return APP_HA_SUCCESS;//Without host auth, all registers are accessible
#endif

	//Check register access
	for (i = 0; i < register_count; i++) {
        if (register_attribute[i].register_name == uw_Address) {
			if(register_attribute[i].access == ACCESS_AFTER_HOST_AUTH){				
			   if(auths_capability.host_auth_done==host_auth_not_done){
					return SDK_E_HOST_AUTH;
				} else{
					break;
				}
			} else {
				break;
			}
		}
    }
	return APP_HA_SUCCESS;
}


/**
* @brief Write data to register. Some registers can only be accessed after host authentication. 
* Certain register write will requires NVM write and will requires NVM programming delay.
* @param uw_Address I2C address of the device
* @param ubp_Data Pointer to data buffer
* @param ub_wr_len Length of data to be write into the register
*/
uint16_t Intf_WriteRegister(uint16_t uw_Address, uint8_t * ubp_Data, uint8_t ub_wr_len )
{
	uint16_t ret = INF_I2C_INIT;	
	//volatile len = ub_wr_len;

	//Check register access for host authentication enabled device
	ret = Can_Access_Register(uw_Address);
	if(APP_HA_SUCCESS!=ret){
		return ret;
	}


	if(ubp_Data == NULL || ub_wr_len == 0){
		return SDK_E_INPUT;
	}

	switch(auths_capability.active_interface){
		case I2C:{
			uint8_t i2c_address=auths_capability.interface.i2c.device_address;
			ret = Is_I2C_address_valid(i2c_address);
			if(ret!=INF_I2C_SUCCESS){
				return ret;
			}

			ret = i2c_bus_command_WD(i2c_address, uw_Address, ub_wr_len, ubp_Data);
			if(INF_I2C_SUCCESS != ret){
				ret = INF_I2C_E_WRITE;
			}else{
				ret = INF_I2C_SUCCESS;
			}
			break;
		}	
		default:
			ret = SDK_E_INTERFACE_UNDEFINED;
			break;
		
	}

	if((ret != INF_I2C_SUCCESS)||(ret != INF_SWI_SUCCESS)){
		return ret;
	}

	return SDK_INTERFACE_SUCCESS;

}

/**
* @brief Read_Register. Some registers can only be accessed after host authentication.
* @param uw_Address Address to be read
* @param ubp_Data Pointer to return data buffer
* @param ub_rd_len Length of data to be read from the register
*/
uint16_t Intf_ReadRegister( uint16_t uw_Address, uint8_t *ubp_Data, uint8_t ub_rd_len)
{
	uint16_t rd_len=ub_rd_len;
	uint16_t ret=SDK_INIT;
	
	//Check register access for host authentication enabled device
	ret = Can_Access_Register(uw_Address);
	if(APP_HA_SUCCESS!=ret){
		return ret;
	}
	

	if(ubp_Data == NULL) {
		return SDK_E_INPUT;
	}

	switch(auths_capability.active_interface){

		case SWI:{

			break;
		}
		

		case I2C:{
			if(rd_len==0){
				rd_len=0xFF;
			}
			uint8_t i2c_address=auths_capability.interface.i2c.device_address;
			ret = Is_I2C_address_valid(i2c_address);
			if(INF_I2C_SUCCESS!=ret){
				return ret;
			}

			ret = i2c_bus_command_RD(i2c_address, uw_Address, rd_len, ubp_Data);
			if(INF_I2C_SUCCESS!= ret){
				return INF_I2C_E_READ;
			}

			ret=INF_I2C_SUCCESS;
			break;
		}

		default:
			ret=SDK_E_INTERFACE_UNDEFINED;
			break;			
	}

	if((ret != INF_I2C_SUCCESS)||(ret != INF_SWI_SUCCESS)){
		return ret;
	}

	return SDK_INTERFACE_SUCCESS;
}
